package mllib;

import org.apache.commons.math.linear.*;
import java.io.*;
import java.util.*;

public class GaussianEstimator implements Estimator{

    private RealVector sampleMean;
    private RealVector variance;
    private int dim;
/*
    private RealMatrix invSigma; // Sigma = covariance matrix
    private RealMatrix sigma;
    private double detSigma;
*/   

    //Builds a Gaussian Distribution around the data ints
    public GaussianEstimator( TrainingSet ts ) 
    {
        dim = ts.dimension();
        sampleMean = ts.mean();
        variance = ts.variance();
        //sigma = ts.covariance();


//        for(int i = 0; i < dim; i++)
//            System.err.println("Variance of dimension "+i+" = "+ variance.getEntry(i) );


        //detSigma = sigma.getDeterminant();
       // invSigma = sigma.inverse();
        

        System.out.println("Gaussian Estimator Created!");        

        //System.out.println( "detSig = " + detSigma);
    } 


    //Builds an Estimator from a file created by calling 'toFile'
    public GaussianEstimator( String filename)
    {
	System.err.println("Reading Gaussian Estimator from file: "+filename);
        try
        {
		    Scanner sc = new Scanner(filename);
        	dim = sc.nextInt();
	        double[] m = new double[dim];
	        double[] v = new double[dim];
	        for( int i = 0; i < dim; ++i)
		{
	            m[i] = sc.nextDouble();
	            v[i] = sc.nextDouble();
		}
                sampleMean = new ArrayRealVector(m);
                variance   = new ArrayRealVector(v);
		
        }catch(Exception e)
	{
	    System.err.println("Gaussian Estimator file is no good");
	 
	}
        /*detSigma = sc.nextDouble();
        double[][] invsig = new double[dim][dim];
        double[] sm = new double[dim];
        for(int i = 0; i < dim; i++)
            for(int j = 0; j< dim; j++)
                invsig[i][j] = sc.nextDouble();
        
        for(int i = 0; i < dim; i ++)
            sm[i] = sc.nextDouble();

        invSigma = new Array2DRowRealMatrix(invsig);
        sampleMean = new ArrayRealVector(sm);
        */
        
    }


    //Prints this Gaussian Estimator to a file.
    public void toFile( String filename)
    {
      try {
            BufferedWriter out = new BufferedWriter(new FileWriter(filename));
            out.write( dim + "\n");
            
            for( int i = 0 ; i < dim; i++)
                    out.write( sampleMean.getEntry(i) + " "+ variance.getEntry(i) + "\n");
            out.close();                    
      }
      catch(IOException e) {}
    }


    //Calculates the probability the vector x is in this Gaussian Distribution
    public double prob( RealVector x) throws Exception
    {
        //double coeff = Math.sqrt(Math.pow(2*Math.PI,x.getDimension())*detSigma); 
        //double mDist = mahalaDistSq( x );
        //return (1 / coeff) * Math.exp(-.5 * mDist);
        RealVector diff = x.subtract(sampleMean);
        double sum = 0;
        for( int i = 0; i < dim; i++){
            if( variance.getEntry(i) != 0)
                sum += diff.getEntry(i) * diff.getEntry(i) / variance.getEntry(i) ;
        }
        return sum;

    } 
/*
    //Returns the Mahalanobis Distance from vector v to this distribution
    //NOT USED
    public double mahalaDistSq( RealVector v)
    {
        RealMatrix diff = new Array2DRowRealMatrix(dim,1);
        diff.setColumnVector( 0, v.subtract(sampleMean) );
        return diff.transpose().multiply(invSigma).multiply(diff).getEntry(0,0);
    }
*/
}
